/**下载、打包、启动  平台工具类 */
const fs = require('fs');
const path = require("path");
const chalk = require("chalk");
const request = require('request');
const process = require('child_process');
const compressing = require('compressing');
const ejs = require('ejs');
const iconv = require('iconv-lite');
const importdb = require(path.join(__dirname, './importdb'));

const cmdExpressSetup = ' npm install express -g ';
const cmdExpressGeneratorSetup = ' npm install express -generator -g ';
const cmdDependSetup = ' npm install ';
const cmdStartpath = 'env/hotdog/server/app';

const envServerPath = 'env/hotdog/server';
const envPublicPath = 'env/hotdog/public';

const projectfile = "project.conf.js";
const envconffile = "env.conf.js";
const mysqlpath = "env/hotdog/hotdog.sql";
const outputfile = "dist/project.conf.js";
const outputfloder = "dist";
const packfloder = "pack";
const envflodder = "env";

const icon_class = {vl:'class:',lg:'6'};
const icon_img = {vl:'img:',lg:'4'};

/**插件在开发环境下的路径 */
var plugpath = "env/hotdog/server/webapp/plugins"
/**操作插件工具在开发环境下的路径 */
var uploadplugpath = "env/hotdog/server/service/uploadplug";

/**平台数据库配置文件路径 */
var envDbConfig = "env/hotdog/server/conf/db.mysql.conf.js";
/**平台环境配置文件路径 */
var envProjectConfig = "env/hotdog/server/conf/project.conf.js";
/**平台 ejs模板文件 */
var envDbEjs = "./../template/env/db.mysql.conf.ejs";
var envProjectEjs = "./../template/env/project.conf.ejs";

/**
 * 初始化Express与Server环境
 */
async function setupExpressAndServerEnv() {
	console.log(chalk.yellow("整体过程较慢，请耐心等待所有操作完成... ..."));
	/**初始化express环境 */
	// await setupExpressEnv();
	/**拉取平台项目 */
	await setupServerEnv();
	/**导入数据 */
	await importdb.importMysql();
	/**修改平台配置 */
	await changeEnvconf();
	/**npm install 初始化平台环境 */
	// console.log(chalk.yellow("正在执行平台环境的 npm install 时间较长 ... ..."));
	await npmInstallEnv();
}

/**在env环境中执行npm install */
async function npmInstallEnv(){
	return new Promise(async function (resolve, reject) {
		try{
			let envServerTruePath =  path.resolve('./',envServerPath);
			// let envPublicTruePath = path.resolve('./',envPublicPath); 
			await execCommandByPath("npm install",{message:'server环境初始化',cwd:envServerTruePath,encoding:'GBK'});
			// await execCommandByPath("npm install",{message:'pulbic环境初始化',cwd:envPublicTruePath,encoding:'GBK'});

			resolve();
		}catch(err){
			console.log(err)
			reject(err)
		}
	});
}

/**修改平台配置 */
async function changeEnvconf() {
	return new Promise(async function (resolve, reject) {
		try {
			//获取env配置文件
			let envconf = require(path.resolve("./", envconffile))

			//获取ejs模板
			let envdbejspath = path.join(__dirname, envDbEjs);
			let envproejspath = path.join(__dirname, envProjectEjs);
			let dbEjsStr = await fs.readFileSync(envdbejspath, 'utf-8');
			let projectEjsStr = await fs.readFileSync(envproejspath, 'utf-8');

			//模板数据转换为界面输入数据
			let dbRet = ejs.render(dbEjsStr, {
				envconf: envconf
			});
			let projectRet = ejs.render(projectEjsStr, {
				envconf: envconf
			});

			//生成文件输出
			let dbpath = path.resolve("./", envDbConfig)
			let propath = path.resolve("./", envProjectConfig)
			await fs.writeFile(dbpath, dbRet, function (err) {
				if (err) {
					console.log(chalk.red("[hotdog_cli ERROR]写入配置文件失败"));
					return console.error(err);
				}
				console.log(chalk.yellow("平台环境 数据库配置文件修改成功！"));
			});
			await fs.writeFile(propath, projectRet, function (err) {
				if (err) {
					console.log(chalk.red("[hotdog_cli ERROR]写入配置文件失败"));
					return console.error(err);
				}
				console.log(chalk.yellow("平台环境 项目配置文件修改成功！"));
			});
			resolve();
		} catch (err) {
			reject(err);
		}
	});
}

/**
 * 启动Express服务
 */
function startExpressService() {
	let nodecmd = process.spawn('node', [cmdStartpath]);
	nodecmd.stdout.on('data', (data) => {
		console.log(`${data}`);
	});
}

/**
 * 打包Output与project文件
 */
async function buildPack() {
	/**判断output 和 pack文件夹是否存在,不存在返回错误 */
	let outputpath = path.resolve("./", outputfloder)
	let packpath = path.resolve("./", packfloder)
	let sourcefile = path.resolve("./", projectfile)
	if ((await fs.existsSync(outputpath)) == false) {
		console.log(chalk.red(`项目输出路径不存在，请检查:${outputpath}`));
		return;
	}
	if ((await fs.existsSync(packpath)) == false) {
		console.log(chalk.red(`项目打包输出文件夹不存在，请检查:${packpath}`));
		return;
	}
	if ((await fs.existsSync(sourcefile)) == false) {
		console.log(chalk.red(`项目配置文件不存在无法拷贝，请检查:${sourcefile}`));
		return;
	}
	/**判断功能和插件图片是否存在 */
	let judgeicon = await judgeFuncIcon(sourcefile).catch((err)=>{
		console.log(err);
	});
	if (!judgeicon) {
		console.log(chalk.red(`[hotdog icon]功能或插件图标不存在，请检查 project.conf.js 配置文件`));
		return;
	}

	/**拷贝项目配置文件 project.conf.js*/
	let lsfile = await fs.readFileSync(sourcefile)
	await fs.writeFileSync(outputfile, lsfile)
	/**获取压缩文件夹名称 name+version */
	let projectconf = require(path.resolve('./', 'project.conf.js'));
	let packname = `${packfloder}/${projectconf.name}_${projectconf.version}.dog`;
	// let packname = `${projectconf.name}_${projectconf.version}.dog`;
	/**压缩文件 */	
	await writeToDogtar(packname).then(()=>{
		console.log(chalk.yellow(`[hotdog]: 文件压缩成功，已压缩至 ${path.resolve(packname)}`));
	})
	.catch((err)=>{
		console.log(err);
	})
}

/**压缩文件 zip */
function writeToDogtar(packname){
	return new Promise(async function(resolve,reject){
		try{
			const tarStream = new compressing.zip.Stream();
			let files = path.resolve('./',outputfloder);
			fs.readdir(files,function(err,path){
				if(err){
					console.log(err);
					throw err;
				}
				path.forEach(async function(path){
					let _path = files+'/'+path;
					tarStream.addEntry(_path);
				});
			});
			let writeStream = fs.createWriteStream(path.resolve(packname));
			await tarStream.pipe(writeStream).on('close',function(){
				resolve();
			})
		}catch(err){
			reject(err);
		}
	})
}
/**校验图标 */
function judgeFuncIcon(sourcefile){
	return new Promise(async function(resolve,reject){
		try{
			let projectconf = require(sourcefile);
			let funcs = projectconf.func;
			//判断插件图标
			let plugicon = projectconf.icon;
			/**是否需要判断 'img:'开头 需要判断 */
			if(!(await judgeHasIcon(plugicon))){
				resolve(false);
				return this;
			}
			//判断功能图标
			await Array.from(funcs,async function(func){
				let funcicon = func.icon;
				if(!(await judgeHasIcon(funcicon))){
					resolve(false);
					return this;
				}
			});
			resolve(true);
			return this;
		}catch(err){
			console.log(err);
			reject(false);
		}
	});
}

/**判断图标是否存在 */
function judgeHasIcon(icon){
	return new Promise(async function (resolve,reject){
		let iconpath = path.resolve("./",'dist/static')
		/**是否需要判断 -- 如果'img:'开头则需要判断 */
		let isjudge = (icon.indexOf(icon_img.vl)=='0')
		if(isjudge){
			icon = icon.substr(icon_img.lg, icon.length);
			let funciconfile = iconpath +'/'+ icon;
			if ((await fs.existsSync(funciconfile)) == false) {
				resolve(false);
			}
		}else if(!(icon.indexOf(icon_class.vl)=='0')){
			resolve(false);
		}
		resolve(true);
	});
}

/**
 * 安装Express环境
 */
function setupExpressEnv() {
	return new Promise(async function (resolve, reject) {
		try {
			await execNpmCommand(cmdExpressSetup, '安装express环境 ');
			await execNpmCommand(cmdExpressGeneratorSetup, '安装express-generator环境 ');
			await execNpmCommand(cmdDependSetup, '安装环境依赖 ');
			resolve();
		} catch (err) {
			reject(err);
		}
	});

}

/**
 * 安装Server环境
 */
function setupServerEnv() {
	return new Promise(async function (resolve, reject) {
		try {
			await loadServerFile();
			await unzipClientFile();
			resolve();
		} catch (err) {
			conslole.log(err);
			reject(err);
		}
	});
}

/**
 * 执行命令工具函数
 */
function execNpmCommand(command, message) {
	return new Promise(function (resolve, reject) {
		process.exec(command, function (error, stdout, stderr) {
			if (error) {
				console.log(chalk.red(`${message}失败`));
				console.log(chalk.red(error));
				reject(error);
			} else if (stderr.length > 0) {
				reject(new Error(stderr.toString()));
			} else {
				console.log(chalk.yellow(`${message}成功`));
				resolve();
			}
		});
	});
}

/**
 * 执行带路径的工具函数
 */
function execCommandByPath(command, data) {
	return new Promise(function (resolve,reject){
		process.exec(command, data, function (error, stdout, stderr) {
			if (error) {
				console.log(chalk.red(data.message + ' 失败'));
				console.log(chalk.red(error));
			} else if (stderr.lenght > 0) {
				console.log('---error--');
			} else {
				console.log(chalk.yellow(data.message + ' 成功'));
			}
		});
	})
}

/**
 * 下载Server文件包
 */
function loadServerFile() {
	return new Promise(function (resolve, reject) {
		let serverconf = require(path.resolve("./", 'env.conf.js'));
		let serverPathFile = serverconf.serverPath + "/" + serverconf.serverFile;
		let localFileUrl = path.resolve("./", envflodder, serverconf.serverFile);
		let wstream = fs.createWriteStream(localFileUrl);
		console.log(chalk.yellow("[hotdog debug]下载环境地址：" + serverPathFile));
		request(serverPathFile).pipe(wstream).on('close', function () {
			console.log(chalk.yellow('下载平台环境资源包 成功'));
			resolve();
		});
	});
}

/**
 * 解压Server文件包
 */
function unzipClientFile() {
	return new Promise(function (resolve, reject) {
		let serverconf = require(path.resolve("./", 'env.conf.js'));
		let localFileUrl = path.resolve("./", envflodder) + "/" + serverconf.serverFile;
		let localFileFolder = path.resolve("./", envflodder);
		compressing.zip.uncompress(localFileUrl, localFileFolder)
			.then(() => {
				console.log(chalk.yellow('解压平台环境资源包 成功'));
				resolve();
			})
			.catch(err => {
				console.error(chalk.red(err));
			})
	});
}

/**安装插件到环境中 */
async function installplug() {
	let projectPlug = require(path.resolve("./", projectfile));
	let uploadplug = require(path.resolve("./", uploadplugpath));
	let newfile = path.resolve("./", path.join(plugpath, projectPlug.name));
	let oldfile = path.resolve("./", outputfloder);
	/**复制文件夹 */
	await uploadplug.installFile(oldfile, newfile);
	/**判断插件是新增还是更新 */
	let flag = await uploadplug.judgeUporIn(projectPlug.uuid);
	let msg = "数据库插入信息错误";
	/**数据库执行上传插件操作 */
	if (flag == '0') {
		await uploadplug.installDatabase(projectPlug);
		msg = "新建插件成功，请按 ctrl+c 结束操作，并通过平台页面将插件加入菜单进行测试";
	} else {
		await uploadplug.uploadDatabase(projectPlug);
		msg = "更新插件成功，请按 ctrl+c 结束操作，并通过平台页面将插件加入菜单进行测试";
	}
	console.log(chalk.yellow(msg));
}

exports.setup = setupExpressAndServerEnv;
exports.build = buildPack;
exports.start = startExpressService;
exports.installplug = installplug;